#include "message_queue.h"

/* insert the message mess in the queue m_queue. Returns 1 in case of success, 0 otherwise */
int32_t insert_message(message_queue* m_queue, message mess){
  int i;
  int count = m_queue->count;
  message* m;
  if(count == MAX_LENGTH_QUEUE) 
    //the queue is full
    return 0;
  //there is at least a free space
  for(i=0;i < MAX_LENGTH_QUEUE; i++){
    m = &(m_queue->queue[i]);
    if(!message_get_in_use(m)){
      //we found an empty place for our message
      messcpy(&m_queue->queue[i],&mess);
      message_set_in_use(m,1);
      //one more message in the queue
      m_queue->count ++;
      break;
    }
  }
  return 1;
}

/* returns the first message and removes it from the queue (if any). Returns 1 if a message is found, 0 otherwise. */
int32_t get_message_first(message_queue* m_queue, message* mess){
  int count = m_queue->count;
  if(!count)
    //the queue is empty
    return 0;
  //when we reach this point, the queue can't be empty
  messcpy(mess,&m_queue->queue[0]);
  remove_message(m_queue, 0);
  return 1;
}

/* returns the first message sent by from and removes it from the queue (if any). Returns 1 if a message is found, 0 otherwise.*/
int32_t get_message_from(message_queue* m_queue, int32_t from, message* mess){
  int count = m_queue->count;
  message* m;
  int i,k = 0, found = 0;
  for(i=0;i<MAX_LENGTH_QUEUE && k < count && !found;i++){
    m = &m_queue->queue[i];
    if(message_get_in_use(m)){
	//we found a message
      k ++;
      if(message_get_from(m) == from){
	//we found THE message
	messcpy(mess,m);
	remove_message(m_queue, i);
	found = 1;
      }
    }
  }
  if(!found)
    return 0;
  return 1;
}

/* returns the first message with the correct priority and removes it from the queue (if any). Returns 1 if a message is found, 0 otherwise. */
int32_t get_message_priority(message_queue* m_queue, int32_t priority, message* mess){
  int count = m_queue->count;
  message* m;
  int i,k = 0, found = 0;
  for(i=0;i<MAX_LENGTH_QUEUE && k < count && !found;i++){
    m = &m_queue->queue[i];
    if(message_get_in_use(m)){
      //we found a message
      k ++;
      if(message_get_priority(m) == priority){
	//we found THE message
	messcpy(mess ,m);
	remove_message(m_queue,i);
	found = 1;
      }
    }
  }
  if(!found)
    return 0;
  return 1;
}

/* removes the message pointed by mess from the queue m_queue. Returns 1 if success, 0 otherwise. */
int32_t remove_message(message_queue* m_queue, int32_t i){
  if(i >= MAX_LENGTH_QUEUE || i < 0)
    //nonexistent index
    return 0;
  message_set_in_use(&(m_queue->queue[i]), 0);
  m_queue->count --;
  return 1;
}

/* sets the status information of the message queue m_queue and blocks the process */
void set_status_information(message_queue* m_queue, int32_t status, int32_t status_data){
  m_queue->status = status;
  m_queue->status_data = status_data;
}

/* checks if the arrival of the message pointed by mess should wake the process to up */
int32_t wake_me_up(message_queue* m_queue,message* m){
  int32_t status = m_queue->status;
  if(status != NOT_WAITING){
    //the process needs to be waken up
    int32_t status_data = m_queue->status_data;
    switch(status){
    case WAITING_FIRST:
      //no filtering
      return 1;
    case WAITING_PRIORITY:
      if(message_get_priority(m) == status_data)
	return 1;
      break;
    case WAITING_FROM:
      if(message_get_from(m) == status_data)
	return 1;
      break;
    default:
      ;
    }
  }
  return 0;
}

/* returns the number of messages in this queue */
int32_t message_queue_get_count(message_queue* m_queue){
  if(m_queue == NULL)
    return 0;
  return m_queue->count;
}
